import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class VendingMachineTest {
	VendingMachine myMachine;
	VendingMachineItem myItem;
	VendingMachineItem myItem2;
	VendingMachineItem myItem3;
	VendingMachineItem myItem4;
	String itemCode = "A";
	VendingMachineItem []slotNumber;
	
	@Before
	public void setUp() throws Exception {
		myMachine = new VendingMachine();
		myItem = new VendingMachineItem("Snickers", 1.00);
		myItem2 = new VendingMachineItem("Twix", 1.00);
		myItem3 = new VendingMachineItem("Milk", 1.00);
		myItem4 = new VendingMachineItem("FruitnNut", 1.00);
	}

	@After
	public void tearDown() throws Exception {
	}
	
	
	@Test
	//test to check whether the in the slot A and C are 
	//the same as item added in slot A and slot C
	public void testAddItem() {
		myMachine.addItem(myItem, VendingMachine.A_CODE);
		myMachine.addItem(myItem2, VendingMachine.B_CODE);
		myMachine.addItem(myItem3, VendingMachine.C_CODE);
		myMachine.addItem(myItem4, VendingMachine.D_CODE);
		assertSame(myItem, myMachine.getItem(VendingMachine.A_CODE));
		assertSame(myItem2, myMachine.getItem(VendingMachine.B_CODE));
		assertSame(myItem3, myMachine.getItem(VendingMachine.C_CODE));
		assertSame(myItem4, myMachine.getItem(VendingMachine.D_CODE));
	}
/*	public void testAddItem_1() {
		//int index = myMachine.getSlotIndex(itemCode);
		myMachine.addItem(myItem, itemCode);
		myItem = slotNumber[index];
		assertEquals("A", itemCode);	
		myMachine.addItem(null, itemCode);
		assertTrue(itemCode != null);
		assertFalse(myItem != null);
		assertTrue(myItem == null);
		assertNotNull(index);
		assertSame(0, index);
	}*/
	
	
	//when two different items are added to the same slot, the 
	//method throws an exception, already occupied.
	@Test(expected = VendingMachineException.class)
	public void testAddTwoItem(){
		myMachine.addItem(myItem, VendingMachine.A_CODE);
		myMachine.addItem(myItem2, VendingMachine.A_CODE);
	}
	//Test to add an item with an invalid code
		@Test(expected=VendingMachineException.class)
		public void testAddItemInvalidCode(){
			myMachine.addItem(myItem, "E_CODE");
		}
	
	//when an item is added and removed from the same slot
	//it checks to assert the value is null, because item has been removed.
	@Test
	public void testRemoveItem(){
		myMachine.addItem(myItem, VendingMachine.A_CODE);
		myMachine.removeItem(VendingMachine.A_CODE);
		assertNull(myMachine.getItem(VendingMachine.A_CODE));
		
	}
	
	//Produce error invalid item code is removed
	@Test(expected = VendingMachineException.class)
	public void testRemoveItem_1(){
		myMachine.removeItem(VendingMachine.D_CODE);
	}
	
	
	@Test
	public void testInsertMoney(){
		//try to insert 0 into machine,this is the bug		 
        myMachine.insertMoney(0);
        assertEquals(0, myMachine.getBalance(), 0.001);   
          
        //test after insert twice money to see is that amount be summed?
        myMachine.insertMoney(3.0);
        myMachine.insertMoney(1.75);
        assertEquals(4.75, myMachine.getBalance(), 0.01); 
        
        //test for finding BUG, when money inserted is less than 1cent, it 
        //shall give error message, but it does not and accepts the .001$
		myMachine.insertMoney(.001);
		assertEquals(4.751, myMachine.getBalance(), .001);
	
		//test to check insert money takes the amount inserted, and calls
		//the get balance method to assert the equality.
		
	}
	@Test
	//test to check insert money function with right values.
	public void testInsertMoney_1(){
	
		myMachine.insertMoney(1.00);
		assertEquals(1.00, myMachine.getBalance(), .001);
	}
	
	//Produce error when value < 0
	@Test(expected = VendingMachineException.class)
	public void testInsertMoney_2(){
		myMachine.insertMoney(-1.00);
	}
	
	
	@Test
	//assertion to equate the amount inserted with the balance in vending machine.
	public void testGetBalance(){
		myMachine.insertMoney(0);
		assertEquals(0, myMachine.getBalance(), .001);
		
	}
	@Test//when money inserted is less than 1.00$
	//for myItem2, it shall return balance .50 
	public void testGetBalance_1(){
		myMachine.insertMoney(.50);
		myMachine.addItem(myItem2, VendingMachine.B_CODE);
		myMachine.makePurchase(VendingMachine.B_CODE);
		assertEquals(.50, myMachine.getBalance(), .001);
	}
	
	//Tests the makePurchase method if a purchase is made for an empty slot.
    @Test
    public void testMakePurchase_EmptySlot()
    {
        assertFalse(myMachine.makePurchase(VendingMachine.A_CODE));

    }
	//test to check the accuracy of amount returned, after making the purchase.
	@Test	 
    public void testReturnChange()

    {	
		myMachine.addItem(myItem, VendingMachine.A_CODE);
		myMachine.insertMoney(5.00);
		myMachine.makePurchase(VendingMachine.A_CODE);
		assertEquals(4.00, myMachine.returnChange(), 0.001);
		assertEquals(0.00, myMachine.getBalance(), .001);

    }
	@Test//This one is a bug, as we can see the balance is zero,
	//and it does not make any sense to call the returnChange(),
	//which returns a value of 0.
	public void testReturnChange_1(){
		myMachine.addItem(myItem, VendingMachine.A_CODE);
		myMachine.insertMoney(1.00);
		myMachine.makePurchase(VendingMachine.A_CODE);
		assertEquals(0, myMachine.returnChange(), 0.001);
	}
	
	}